package com.ruoyi.business.processIou.service;

import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.enums.EnumFeeType;
import com.ruoyi.bizsys.mapper.AccountFlowMapper;
import com.ruoyi.bizsys.mapper.LoanIouMapper;
import com.ruoyi.bizsys.mapper.LoanOffsetMapper;
import com.ruoyi.bizsys.mapper.RepaymentOrderMapper;
import com.ruoyi.bizsys.service.ICreditAccountService;
import com.ruoyi.bizsys.service.ILoanOverflowService;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.bizsys.vo.LoanIouExtVo;
import com.ruoyi.business.service.IBLoanInfoService;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @author wqg
 * @description MoninflyFinace的回溯代码
 * @date 2022/3/23
 */
@Slf4j
@Component
public class MoninflyFinaceService {
    @Resource
    LoanIouMapper loanIouMapper;
    @Resource
    LoanOffsetMapper loanOffsetMapper;
    @Autowired
    AccountFlowMapper accountFlowMapper;

    @Autowired
    ILoanOverflowService iLoanOverflowService;

    @Autowired
    ICreditAccountService creditAccountService;
    @Autowired
    RepaymentOrderMapper repaymentOrderMapper;

    @Autowired
    @Lazy
    IBLoanInfoService loanInfoService;
    /***显示当天的还款金额*/
    private static ThreadLocal<BigDecimal> amtOrgLocal = new ThreadLocal<>();
    /***累计罚息-用于扣除*/
    private static ThreadLocal<BigDecimal> lateFeePlusLocal = new ThreadLocal<>();
    /***累计罚息-一直累计*/
    private static ThreadLocal<BigDecimal> lateFeePlusAllLocal = new ThreadLocal<>();
    /***按天存储的offset*/
    private static ThreadLocal<TreeMap<Integer, List<LoanOffset>>> dayMapLocal = new ThreadLocal<>();
    /***原始数据*/
    private static ThreadLocal<LoanIou> loanIouOrgLocal = new ThreadLocal<>();
    /***当天iou*/
    private static ThreadLocal<LoanIou> loanIouDay = new ThreadLocal<>();

    private static ThreadLocal<Boolean> iouStatusSuccess = new ThreadLocal<>();

//    @PostConstruct
//    public void test() {
//        init("1005jju");
//    }

    /**
     * 全量计算回溯，返回iou数据
     *
     * @param loanSerialNo
     * @return
     */
    @Transactional
    public LoanIou init(String loanSerialNo) {
        setLocalData();
        log.info(Thread.currentThread().getName() + "开始处理：{}", loanSerialNo);
        LoanIouExtVo loanIou = loanIouMapper.findOneByLoanSerialNo(loanSerialNo);
        // 保留原始数据，用于对比数据
        BeanUtils.copyProperties(loanIou, loanIouOrgLocal.get());
        log.info("产品信息：periodNum：{},loanAmt:{},interest：{},serviceFee：{},dateLateFee:{},lateFeeMaxDays:{}"
                , loanIou.getPeriodNum(), loanIou.getLoanAmt()
                , loanIou.getInterest(), loanIou.getServiceFee()
                , loanIou.getDateLateFee(), loanIou.getLateFeeMaxDays());
        doProcessOffset(loanIou);
        return loanIou;
    }

    /**
     * 初始化local变量
     */
    private void setLocalData() {
        loanIouOrgLocal.set(new LoanIou());
        loanIouDay.set(new LoanIou());
        amtOrgLocal.set(BigDecimal.ZERO.setScale(6, BigDecimal.ROUND_DOWN));
        lateFeePlusLocal.set(BigDecimal.ZERO.setScale(6, BigDecimal.ROUND_DOWN));
        lateFeePlusAllLocal.set(BigDecimal.ZERO.setScale(6, BigDecimal.ROUND_DOWN));
        dayMapLocal.set(new TreeMap<>());
        iouStatusSuccess.set(false);
    }

    /**
     * 手动删除，防止内存泄漏
     */
    private void removeLocalData() {
        loanIouOrgLocal.remove();
        loanIouDay.remove();
        amtOrgLocal.remove();
        lateFeePlusLocal.remove();
        lateFeePlusAllLocal.remove();
        dayMapLocal.remove();
        iouStatusSuccess.remove();
    }

    /**
     * 开始计算
     *
     * @param loanIou
     */
    private void doProcessOffset(LoanIouExtVo loanIou) {
        // dayMap key 天 value 还款amt
        List<LoanOffset> loanOffsetList = loanOffsetMapper.selectListForIou(loanIou.getLoanSerialNo());
        if (!CollectionUtils.isEmpty(loanOffsetList)) {
            dayMapLocal.set(loanOffsetListToTreeMap(loanOffsetList));
        }
        // 借据表的period_num周期内，利息是由本金*周期天数*利息率，在0天生成，服务费由本金*服务费率，在0天生成。
        // 如果发生还款优先偿还利息，然后才是服务费，一旦偿还到0后面一直保持为0；
        loanIou.setLateFee(BigDecimal.ZERO); // 方便打印数据 周期内还款不会产生罚息
        int periodNum = loanIou.getPeriodNum();
        for (int i = 0; i <= periodNum + loanIou.getLateFeeGracePeriod(); i++) {
            if ( !iouStatusSuccess.get() && i <= loanIou.getNowDayIndex()) {
                doProcessInPeriodNumByDay(i, dayMapLocal.get().get(i), loanIou);
            }
        }

        if (iouStatusSuccess.get()) {
            log.info(loanIou.getLoanSerialNo() + ":周期内还款完成～没有逾期");
            doIouDone(loanIou, loanOffsetList);
            return;
        }
        // 罚息计算
        // 存在还款 进行计算 进行罚息 < 优先偿还利息，然后才是服务费，一旦偿还到0后面一直保持为0 >
        log.info(loanIou.getLoanSerialNo() + "-滞纳金按日收费宽限期 {} 天", loanIou.getLateFeeGracePeriod());
        for (int i = periodNum + 1 + loanIou.getLateFeeGracePeriod(); i <= periodNum + loanIou.getLateFeeMaxDays(); i++) {
            // 先进行第一个部分计算
            if ( !iouStatusSuccess.get() && i <= loanIou.getNowDayIndex()) {
                doProcessInLateFree(i, dayMapLocal.get().get(i), loanIou);
            }
        }
        log.info("大于LateFeeMaxDays的计算，大于 产品限制滞纳金天数后，取滞纳金限制天数最后一天");

        doProcessOverMaxDay(dayMapLocal.get(), loanIou);

        // 判断iou是否数据正确进行更新
        // if(loanIouOrgLocal.get().getLateFee().compareTo(lateFeePlusAllLocal.get())!=0){
        if (!iouStatusSuccess.get() && compareIouRepaid(loanIouOrgLocal.get(), loanIou, lateFeePlusLocal.get(), lateFeePlusAllLocal.get())) {
            log.info(loanIou.getLoanSerialNo() + " 》》》》》》iou还款利息错误");
            // 进行更新iou操作 和记录变更记录
            updateAndCreateRecordIou(loanIouOrgLocal.get(), lateFeePlusLocal.get(), lateFeePlusAllLocal.get(), loanIou,null);
        }

        doIouDone(loanIou, loanOffsetList);

//
//        // 其他的数据进入溢缴款
//        if(iouStatusSuccess.get() && dayMapLocal.get().get(i) != null){
//            // 当天存在还款
//            log.info(
//                    loanIou.getLoanSerialNo() + " [ " + DateUtils.dateTime(DateUtils.addDays(loanIou.getCreateTime(), i)) + " ]" +
//                            "罚息计算在第{}天第{}次:还钱：{},进入溢缴款", i, j, amtOrgLocal.get());
//            // 进入溢缴款
//            // 修改repayMentOrder 和loan_offset 为失败
//            insertLoanOverFlowUpdateFlaid(dayMapLocal.get().get(i).get(j));
//            return;
//        }
    }

    /**
     * 结清后操作
     * @param loanIou
     * @param loanOffsetList
     */
    private void doIouDone(LoanIouExtVo loanIou, List<LoanOffset> loanOffsetList) {
        if (iouStatusSuccess.get()){
            // 大于getSettleDate的进入溢缴款
            for (int i = 0; i < loanOffsetList.size(); i++) {
                LoanOffset loanOffset = loanOffsetList.get(i);
                String leftTime = DateUtils.formatDate(loanOffset.getPayTimeOrder(), "yyyy-MM-dd HH:mm:ss");
                String rightTime = DateUtils.formatDate(loanIou.getSettleDate(), "yyyy-MM-dd HH:mm:ss");
                log.info("leftTime:"+leftTime);
                log.info("rightTime:"+rightTime);
                if(DateUtils.compareTimes(leftTime,rightTime,"yyyy-MM-dd HH:mm:ss")>0){
                    // 支付时间大余iou时间进行冲账
                    insertLoanOverFlowUpdateFlaid(loanOffset);
                }
            }
            // 更新账户汇总信息
            CreditAccount account = creditAccountService.getNormalAcountOnLoan(loanIou.getCustNo());
            loanInfoService.updateAccount(account);
        }
        removeLocalData();
        //int a = 10/0;
        log.info("-----------:结束");
    }

    /**
     * @param orgLoanIou     数据库源数据
     * @param loanIouNow     temp数据
     * @param lateFeePlus    剩余滞纳金
     * @param lateFeePlusAll 总滞纳金
     * @return
     */
    private boolean compareIouRepaid(LoanIou orgLoanIou, LoanIou loanIouNow, BigDecimal lateFeePlus, BigDecimal lateFeePlusAll) {
        if (orgLoanIou.getLateFee().compareTo(lateFeePlusAll.setScale(4, BigDecimal.ROUND_DOWN)) != 0) {
            return true;
        }
        if (orgLoanIou.getRepaidLateFee().compareTo(lateFeePlusAll.subtract(lateFeePlus).setScale(4, BigDecimal.ROUND_DOWN)) != 0) {
            return true;
        }
        if (orgLoanIou.getRepaidInterest().compareTo(orgLoanIou.getLoanInterest().subtract(loanIouNow.getInterest()).setScale(4, BigDecimal.ROUND_DOWN)) != 0) {
            return true;
        }
        if (orgLoanIou.getRepaidServiceFee().compareTo(orgLoanIou.getServiceFee().subtract(loanIouNow.getServiceFee()).setScale(4, BigDecimal.ROUND_DOWN)) != 0) {
            return true;
        }
        if (orgLoanIou.getRepaidPrincipal().compareTo(orgLoanIou.getLoanPrincipal().subtract(loanIouNow.getLoanAmt()).setScale(4, BigDecimal.ROUND_DOWN)) != 0) {
            return true;
        }
        return false;
    }

    /**
     * 还款期限内按天进行计算
     *
     * @param i       是第几天
     * @param dayList
     * @param loanIou
     */
    private void doProcessInPeriodNumByDay(int i, List<LoanOffset> dayList, LoanIouExtVo loanIou) {
        // 本期还的钱
        BigDecimal amt = CollectionUtils.isEmpty(dayList) ? BigDecimal.ZERO : dayList.get(0).getAmt().setScale(6, BigDecimal.ROUND_DOWN);
        if (amt.compareTo(BigDecimal.ZERO) != 0) {
            for (int j = 0; j < dayList.size(); j++) {
                amt = dayList.get(j).getAmt().setScale(6, BigDecimal.ROUND_DOWN);
                // 利息计算
                amtOrgLocal.set(amt);
                processInterest(i, j, amt, loanIou);
            }
        } else {
            amtOrgLocal.set(BigDecimal.ZERO);
            endProcess(i, 0, amt, loanIou);
        }
    }

    /**
     * 超期后进行罚息计算等
     *
     * @param i
     * @param dayList
     * @param loanIou
     */
    private void doProcessInLateFree(int i, List<LoanOffset> dayList, LoanIouExtVo loanIou) {
        // 计算罚息 罚息的计算只依照前一天的本金(前一天的本金 * 罚息利率dateLateFee )
        BigDecimal lateFee = loanIou.getLoanAmt().multiply(loanIou.getDateLateFee()).setScale(6, BigDecimal.ROUND_DOWN);
        // 今日罚息
        loanIou.setLateFee(lateFee);
        // 加上今天的罚息
        lateFeePlusLocal.set(lateFeePlusLocal.get().add(lateFee).setScale(6, BigDecimal.ROUND_DOWN));
        lateFeePlusAllLocal.set(lateFeePlusAllLocal.get().add(lateFee));
        BigDecimal amt = CollectionUtils.isEmpty(dayList) ? BigDecimal.ZERO : dayList.get(0).getAmt().setScale(6, BigDecimal.ROUND_DOWN);
        if (amt.compareTo(BigDecimal.ZERO) != 0) {
            for (int j = 0; j < dayList.size(); j++) {
                amt = dayList.get(j).getAmt().setScale(6, BigDecimal.ROUND_DOWN);
                amtOrgLocal.set(amt);
                processLateFree(i, j, amt, loanIou);
            }
        } else {
            amtOrgLocal.set(BigDecimal.ZERO);
            endProcess(i, 0, amt, loanIou);
        }
    }

    /**
     * 超期还款，滞纳金取最后一个
     *
     * @param dayMap
     * @param loanIou
     */
    private void doProcessOverMaxDay(TreeMap<Integer, List<LoanOffset>> dayMap, LoanIouExtVo loanIou) {
        if(iouStatusSuccess.get()){
            return;
        }

        int periodNum = loanIou.getPeriodNum();
        for (int day : dayMap.keySet()) {
            // 取大于最大限制日的还款进行计算
            if (day > (periodNum + loanIou.getLateFeeMaxDays())) {
                doProcessOverMaxDayDetial(day, loanIou, dayMap.get(day));
            }

        }
    }

    private void doProcessOverMaxDayDetial(int i, LoanIouExtVo loanIou, List<LoanOffset> dayMap) {
        for (int j = 0; j < dayMap.size(); j++) {
            // 今日罚息不再累计算，lateFeePlus总罚息就是当前总罚息
            loanIou.setLateFee(BigDecimal.ZERO);
            amtOrgLocal.set(dayMap.get(j).getAmt());
            processLateFree(i, j, amtOrgLocal.get(), loanIou);
        }
    }


    /**
     * 罚息扣除计算
     *
     * @param i
     * @param amt
     * @param loanIou
     */
    private void processLateFree(int i, int j, BigDecimal amt, LoanIouExtVo loanIou) {
        // 小于等于罚息
        if (lateFeePlusLocal.get().compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(lateFeePlusLocal.get()) <= 0) {
            lateFeePlusLocal.set(lateFeePlusLocal.get().subtract(amt).setScale(6, BigDecimal.ROUND_DOWN));// 剩余罚息
            loanIou.setOffsetLateFee(amt);
            endProcess(i, j, amt, loanIou);
            return;
        }
        if (lateFeePlusLocal.get().compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(lateFeePlusLocal.get()) == 1) {
            amt = amt.subtract(lateFeePlusLocal.get()).setScale(6, BigDecimal.ROUND_DOWN);// 扣除罚息
            loanIou.setOffsetLateFee(lateFeePlusLocal.get());
            lateFeePlusLocal.set(BigDecimal.ZERO);// 罚息还完
            // 进行利息等计算
        }
        processInterest(i, j, amt, loanIou);
        //  计算是否扣除罚息------end
    }


    /**
     * 计算利息
     *
     * @param i
     * @param j       当天第几次还款0+1
     * @param amt
     * @param loanIou
     */
    private void processInterest(int i, int j, BigDecimal amt, LoanIouExtVo loanIou) {
        BigDecimal interest = loanIou.getInterest();
        if (interest.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(interest) <= 0) {
            // 小于等于利息
            // 剩余利息
            loanIou.setInterest(interest.subtract(amt).setScale(6, BigDecimal.ROUND_DOWN));
            loanIou.setOffsetInterest(amt);
            endProcess(i, j, amt, loanIou);
            return;
        }
        if (interest.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(interest) == 1) {
            // 大于利息
            // 进行利息扣除
            amt = amt.subtract(interest).setScale(6, BigDecimal.ROUND_DOWN);
            // 利息还完了
            loanIou.setInterest(BigDecimal.ZERO);
            loanIou.setOffsetInterest(interest);
        }
        // 支付了利息~进行服务费计算
        processServiceFee(i, j, amt, loanIou);
    }

    /**
     * 支付了利息~进行服务费计算
     *
     * @param i
     * @param loanIou
     */
    private void processServiceFee(int i, int j, BigDecimal amt, LoanIouExtVo loanIou) {
        // 支付了利息~进行服务费计算
        BigDecimal serviceFee = loanIou.getServiceFee();
        if (serviceFee.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(serviceFee) <= 0) {
            // 小于服务费
            serviceFee = serviceFee.subtract(amt).setScale(6, BigDecimal.ROUND_DOWN);
            // 剩余服务费
            loanIou.setServiceFee(serviceFee);
            loanIou.setOffsetServiceFee(amt);
            endProcess(i, j, amt, loanIou);
            return;
        }
        if (serviceFee.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(serviceFee) == 1) {
            // 大于服务费
            // 扣除服务费
            amt = amt.subtract(serviceFee).setScale(6, BigDecimal.ROUND_DOWN);
            // 服务费还完了
            loanIou.setServiceFee(BigDecimal.ZERO);
            loanIou.setOffsetServiceFee(serviceFee);
        }
        // 开始还本金
        processLoanAmt(i, j, amt, loanIou);
    }

    /**
     * 开始还本金
     *
     * @param i
     * @param loanIou
     */
    private void processLoanAmt(int i, int j, BigDecimal amt, LoanIouExtVo loanIou) {
        BigDecimal loanAmt = loanIou.getLoanAmt();
        // 小于本金
        if (loanAmt.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(loanAmt) <= 0) {
            // 剩余本金
            loanAmt = loanAmt.subtract(amt).setScale(6, BigDecimal.ROUND_DOWN);
            loanIou.setLoanAmt(loanAmt);
            loanIou.setOffsetPrincipal(amt);
            amt = BigDecimal.ZERO;
            endProcess(i, j, amt, loanIou);
            return;
        }
        // 大于本金
        if (loanAmt.compareTo(BigDecimal.ZERO) != 0 && amt.compareTo(loanAmt) == 1) {
            // 还完了
            amt = amt.subtract(loanAmt).setScale(6, BigDecimal.ROUND_DOWN);
            loanIou.setLoanAmt(BigDecimal.ZERO);
            loanIou.setOffsetPrincipal(loanAmt);
            endProcess(i, j, amt, loanIou);
            log.info(loanIou.getLoanSerialNo() + ":存在多还款多{}", amt);
        }


    }

    /**
     * 计算每一天的最后结果进行处理
     *
     * @param i
     * @param amt
     * @param loanIou
     */
    private void endProcess(int i, int j, BigDecimal amt, LoanIouExtVo loanIou) {
        log.info(
                loanIou.getLoanSerialNo() + " [ " + DateUtils.dateTime(DateUtils.addDays(loanIou.getCreateTime(), i)) + " ]罚息计算在第{}天第{}次:还钱：{},剩余本金：{},剩余利息：{},剩余服务费：{}，当天产生罚息:{},还款后剩余总罚息：{}，产生罚息：{}"
                , i, j, amtOrgLocal.get(), loanIou.getLoanAmt(), loanIou.getInterest(), loanIou.getServiceFee()
                , loanIou.getLateFee() == null ? BigDecimal.ZERO : loanIou.getLateFee()
                , lateFeePlusLocal.get(), lateFeePlusAllLocal.get());
        //记录每天的罚息到账目流水数据
        createAccountFlow(loanIou, i, j);

        if(dayMapLocal.get().get(i) != null
                && dayMapLocal.get().get(i).get(j).getActionType().equals(RepaymentOrder.ACTION_TYPE_FINANCE)){
            // 财务回溯还款需要更新前一天的iou到repaymentOrder 是先创建的
            updateRepaymentOrderFiance(loanIou);
        }

        // 存在还款，判断还款数据是否正确
        if (dayMapLocal.get().get(i) != null
                && compareRepaidAmt(dayMapLocal.get().get(i).get(j), loanIouDay.get(), lateFeePlusAllLocal.get())) {
            log.info(loanIou.getLoanSerialNo() + " -----------在第{}天还款计算错误"
                    , i, dayMapLocal.get().get(i).get(j).getLateFee(), lateFeePlusAllLocal.get());
            updateAndCreateRecord(dayMapLocal.get().get(i).get(j), lateFeePlusLocal.get(), lateFeePlusAllLocal.get(), loanIou, loanIouDay.get());
        }

        // 记录当天的数据iou当前快照
        loanIouDay.get().setRepaidLateFee(lateFeePlusAllLocal.get().subtract(lateFeePlusLocal.get()));
        loanIouDay.get().setRepaidInterest(loanIouOrgLocal.get().getInterest().setScale(6, BigDecimal.ROUND_DOWN).subtract(loanIou.getInterest().setScale(6, BigDecimal.ROUND_DOWN)));
        loanIouDay.get().setRepaidServiceFee(loanIouOrgLocal.get().getServiceFee().subtract(loanIou.getServiceFee()));
        loanIouDay.get().setRepaidPrincipal(loanIouOrgLocal.get().getLoanPrincipal().subtract(loanIou.getLoanAmt()));
        setZeroOffset(loanIou);

        // 判断本金是否还完
        if(loanIou.getLoanAmt().compareTo(BigDecimal.ZERO)==0){
            // 判断是否有多余的，溢缴款存
            if(amt.compareTo(BigDecimal.ZERO)>0){
                log.info(loanIou.getLoanSerialNo()+" 溢缴款，{},存入溢缴款",amt);
                RepaymentOrder repaymentOrder = repaymentOrderMapper.getDetail(dayMapLocal.get().get(i).get(j).getRepaymentNo());
                doLoanOverFlow(dayMapLocal.get().get(i).get(j), repaymentOrder,amt);
            }
            // 进行结清操作
            iouStatusSuccess.set(true);
            log.info(loanIou.getLoanSerialNo() + " 开始结清操作");
            // 进行更新iou操作 和记录变更记录
            updateAndCreateRecordIou(loanIouOrgLocal.get(), lateFeePlusLocal.get(), lateFeePlusAllLocal.get(), loanIou,dayMapLocal.get().get(i).get(j));
        }

    }

    private void updateRepaymentOrderFiance(LoanIouExtVo loanIou) {
        RepaymentOrder repaymentOrder = new RepaymentOrder();
        BigDecimal needTotal = loanIou.getLoanPrincipal().add(loanIou.getLoanInterest()).add(loanIou.getServiceFee()).add(loanIou.getLateFee());
        BigDecimal repaidTotal = loanIou.getRepaidPrincipal().add(loanIou.getRepaidInterest()).add(loanIou.getRepaidServiceFee()).add(loanIou.getRepaidLateFee());
        // 计算减免金额
        BigDecimal reduceAmt = loanIou.getReduceAmt() == null ? BigDecimal.ZERO : loanIou.getReduceAmt();
        BigDecimal repaymentAmt = needTotal.subtract(repaidTotal).subtract(reduceAmt);
        if (repaymentAmt.compareTo(BigDecimal.ZERO) == 1) {//如果金额大于0
            repaymentOrder.setRepaymentAmt(repaymentAmt.setScale(0, BigDecimal.ROUND_UP));
        }
        repaymentOrder.setReduceFee(reduceAmt);
        repaymentOrder.setLoanPrincipal(loanIou.getLoanPrincipal());
        repaymentOrder.setRepaidPrincipal(loanIou.getRepaidPrincipal());
        repaymentOrder.setServiceFee(loanIou.getServiceFee());
        repaymentOrder.setRepaidServiceFee(loanIou.getServiceFee());
        repaymentOrder.setLoanInterest(loanIou.getLoanInterest());
        repaymentOrder.setRepaidInterest(loanIou.getLoanInterest());
        repaymentOrder.setLateFee(loanIou.getLateFee());
        repaymentOrder.setRepaidLateFee(loanIou.getRepaidLateFee());
        repaymentOrderMapper.updateById(repaymentOrder);
    }

    private void insertLoanOverFlowUpdateFlaid(LoanOffset loanOffset){
        RepaymentOrder repaymentOrder = repaymentOrderMapper.getDetail(loanOffset.getRepaymentNo());
        // 设置失效
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_FAIL);
        repaymentOrder.setRemark("财务回溯，前面还款导致结清，后面的还款冲溢缴款");
        repaymentOrderMapper.updateById(repaymentOrder);
        loanOffset.setLoanOffsetStatus(0);
        loanOffset.setRemark("财务回溯，前面还款导致结清，后面的还款冲溢缴款");
        loanOffsetMapper.updateById(loanOffset);
        doLoanOverFlow(loanOffset, repaymentOrder,loanOffset.getAmt());
    }

    private void doLoanOverFlow(LoanOffset loanOffset, RepaymentOrder repaymentOrder,BigDecimal amt) {
        LoanOverflow loanOverflow = new LoanOverflow();
        loanOverflow.setChangeAmount(amt);
        loanOverflow.setCustNo(loanOffset.getCustNo());
        loanOverflow.setOverflowTime(loanOffset.getPayTime());
        loanOverflow.setType(BizConstants.OVERFLOW_TYPE_FINANCE_CAL);
        loanOverflow.setAccountReference(loanOffset.getCustNo());
        loanOverflow.setTransactionReference(repaymentOrder.getPayTransSerialNo());
        iLoanOverflowService.insertLoanOverflow(loanOverflow);
        //修改用户溢缴金额
        // creditAccountService.updateOverflowAmount(loanOffset.getCustNo(),amt);
    }

    public void updateAndCreateRecordIou(LoanIou loanIouOrg, BigDecimal lateFeePlus , BigDecimal lateFeePlusAll, LoanIou loanIou,LoanOffset loanOffset) {
        processNewIou(loanIouOrg,loanIou,lateFeePlus,lateFeePlusAll);
        if(iouStatusSuccess.get()){
            loanIou.setIouStatus(LoanIou.LOAN_IOU_STATUS_SETTLE);
        }
        if(null!=loanOffset){
            loanIou.setSettleDate(loanOffset.getPayTimeOrder());
        }
        loanIouMapper.updateById(loanIou);
    }

    /**
     * 计算新的数据
     * @param loanIouOrg
     * @param loanIou
     * @param lateFeePlusAll
     */
    private void processNewIou(LoanIou loanIouOrg, LoanIou loanIou, BigDecimal lateFeePlus,BigDecimal lateFeePlusAll) {
        // 最新的总罚息
        loanIou.setLateFee(lateFeePlusAll);
        // 已还罚息
        loanIou.setRepaidLateFee(lateFeePlusAll.subtract(lateFeePlus));
        // 已还总利息
        loanIou.setRepaidInterest(loanIouOrg.getInterest().subtract(loanIou.getInterest()));
        // 总利息
        loanIou.setLoanInterest(loanIouOrg.getLoanInterest());
        loanIou.setInterest(loanIouOrg.getInterest());
        // 已还服务费

        loanIou.setRepaidServiceFee(loanIouOrg.getServiceFee().subtract(loanIou.getServiceFee()));
        // 总服务费
        loanIou.setServiceFee(loanIouOrg.getServiceFee());
        // 已还本金
        loanIou.setRepaidPrincipal(loanIouOrg.getLoanAmt().subtract(loanIou.getLoanAmt()));
        // 本金
        loanIou.setLoanPrincipal(loanIouOrg.getLoanAmt());
        loanIou.setLoanAmt(loanIouOrg.getLoanAmt());
        //等于0，则b1=b2；
        //等于 1 ，则b1>b2 ;
        //等于-1，则b1<b2。
        loanIou.setFeeRemissionAmt(BigDecimal.ZERO);// 正常回溯不需要这个数据
        loanIou.setOverdueAmount(LoanIou.calculationOverdueAmount(loanIou));

    }

    public void updateAndCreateRecord(LoanOffset loanOffset, BigDecimal lateFeePlus, BigDecimal lateFeePlusAll, LoanIouExtVo loanIou, LoanIou iouBeforeDay) {
        processNewOffset(loanOffset,loanIou,lateFeePlus,lateFeePlusAll,iouBeforeDay);
        loanOffsetMapper.updateById(loanOffset);
    }

    /**
     * 计算新的数据
     * @param loanOffset
     * @param loanIou
     * @param lateFeePlus
     * @param lateFeePlusAll
     */
    private void processNewOffset(LoanOffset loanOffset, LoanIouExtVo loanIou, BigDecimal lateFeePlus, BigDecimal lateFeePlusAll,LoanIou iouBeforeDay) {
        // 最新的总罚息
        loanOffset.setLateFee(lateFeePlusAll);
        // 上次iou已还罚息
        loanOffset.setRepaidLateFee(iouBeforeDay.getRepaidLateFee());
        // 上次iou已还总利息
        loanOffset.setRepaidInterest(iouBeforeDay.getRepaidInterest());
        // 上次iou已还服务费
        loanOffset.setRepaidServiceFee(iouBeforeDay.getRepaidServiceFee());
        // 上次iou已还本金
        loanOffset.setRepaidPrincipal(iouBeforeDay.getRepaidPrincipal());
        loanOffset.setReduceAmt(BigDecimal.ZERO);//正常流程下不需要这个数据
        loanOffset.setOffsetLateFee(loanIou.getOffsetLateFee());
        loanOffset.setOffsetServiceFee(loanIou.getOffsetServiceFee());
        loanOffset.setOffsetInterest(loanIou.getOffsetInterest());
        loanOffset.setOffsetPrincipal(loanIou.getOffsetPrincipal());
    }



    /**
     * 记录还款罚息
     *
     * @param loanIou
     */
    private void createAccountFlow(LoanIouExtVo loanIou, int i, int j) {
        // 判断每天的第0次就行
        if (j > 0) {
            return;
        }
        BigDecimal lateFee = loanIou.getLateFee() == null ? BigDecimal.ZERO : loanIou.getLateFee();
        if (lateFee.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        AccountFlow accountFlow = new AccountFlow();
        accountFlow.setCustNo(loanIou.getCustNo());
        accountFlow.setRelativeSerialNo(loanIou.getLoanSerialNo());
        accountFlow.setTransferChannel("");
        // 发生的时间 天数+iou创建的时间
        Date transDay = DateUtils.addDays(loanIou.getCreateTime(), i);
        accountFlow.setTransferTime(transDay);
        // 时间判断的
        accountFlow.setBetweenLeft(DateUtils.betweenArr(transDay)[0]);
        // 时间判断的
        accountFlow.setBetweenRight(DateUtils.betweenArr(transDay)[1]);
        accountFlow.setOffsetTime(new Date());
        accountFlow.setDataSource("loan_iou、loan_offset");
        accountFlow.setAmt(lateFee);
        accountFlow.setFeeType(EnumFeeType.REPAID_LATE_FEE.getCode());
        if (null == accountFlowMapper.selectByTransTime(accountFlow)) {
            accountFlowMapper.insertByIndex(accountFlow);
        }

    }

    /**
     * 冲账到那一项归零
     *
     * @param loanIou
     */
    private void setZeroOffset(LoanIouExtVo loanIou) {
        loanIou.setOffsetLateFee(BigDecimal.ZERO);
        loanIou.setOffsetServiceFee(BigDecimal.ZERO);
        loanIou.setOffsetInterest(BigDecimal.ZERO);
        loanIou.setOffsetPrincipal(BigDecimal.ZERO);
    }

    /**
     * @param orgOffset     当前还款的数据库数据
     * @param beforeloanIou 前一次还款iou快照
     * @param lateFee
     * @return
     */
    private boolean compareRepaidAmt(LoanOffset orgOffset, LoanIou beforeloanIou, BigDecimal lateFee) {
        if (orgOffset.getLateFee().compareTo(lateFee.setScale(4, BigDecimal.ROUND_DOWN)) != 0) {
            return true;
        }
        if (null != beforeloanIou.getRepaidLateFee() && orgOffset.getRepaidLateFee().compareTo(beforeloanIou.getRepaidLateFee()) != 0) {
            return true;
        }
        if (null != beforeloanIou.getRepaidInterest() && orgOffset.getRepaidInterest().compareTo(beforeloanIou.getRepaidInterest()) != 0) {
            return true;
        }
        if (null != beforeloanIou.getRepaidServiceFee() && orgOffset.getRepaidServiceFee().compareTo(beforeloanIou.getRepaidServiceFee()) != 0) {
            return true;
        }
        if (null != beforeloanIou.getRepaidPrincipal() && orgOffset.getRepaidPrincipal().compareTo(beforeloanIou.getRepaidPrincipal()) != 0) {
            return true;
        }
        return false;
    }


    private TreeMap<Integer, List<LoanOffset>> loanOffsetListToTreeMap(List<LoanOffset> loanOffsetList) {
        TreeMap<Integer, List<LoanOffset>> collect = loanOffsetList.stream()
                .collect(
                        Collectors.groupingBy(
                                LoanOffset::getRepayDayIndex,
                                TreeMap::new,
                                Collectors.toList()
                        ));
        return collect;
    }
}
